package by.kniazhych.core.server.local.ai {
	import by.kniazhych.core.constants.PeaceType;
	import by.kniazhych.core.constants.UserColor;
	import by.kniazhych.core.data.game.PeacePosition;
	import by.kniazhych.core.server.local.core.IMotion;
	import by.kniazhych.core.server.local.core.Motion;
	import by.kniazhych.core.server.local.data.MotionCommand;
	import by.kniazhych.core.server.local.events.RequestMotionEvent;
	import by.kniazhych.core.server.local.events.ServerGameEvent;
	import by.kniazhych.core.server.local.data.BoardData;
	import by.kniazhych.core.server.local.logic.LogicController;
	import by.kniazhych.core.server.local.rules.GameRules;
	import by.kniazhych.core.server.local.rules.IPlayer;
	import by.kniazhych.core.server.local.rules.Player;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.getTimer;
	import flash.utils.setTimeout;
	
	/**
	 * ...
	 * @author Boutylin Mikhail
	 */
	
	
	
	public class AI extends Player{
		
		//private var _controller:TestLogicController;
		private static const ACTIONS_CONSTRUCTED:String = "actionsConstructed";
		private var _possibleMotions:Vector.<IMotion>;
		private var _t:uint;
		private var _maxWeight:Number;
		
		public function AI(data:BoardData, color:uint) {
			super(data, color);
			//_controller = new TestLogicController();
			_data.addEventListener(ServerGameEvent.PLAYER_CHANGED, _onPlayerChanged);
			_data.addEventListener(ServerGameEvent.PEACE_CHANGED, _onPeaceChanged);
			super.addEventListener(ACTIONS_CONSTRUCTED, _onActionsConstructed);
		}
		
		public function doMotion():void {
			
			var dataClone:BoardData = _data;
			_controller.updateData(dataClone);
			
			_constructPossibleMotions(dataClone);
			
		}
		
		private function _onActionsConstructed(e:Event):void {
			var possibleMotions:Vector.<IMotion> = _possibleMotions;
			if (possibleMotions.length) { //у гульні няма пата
				var finalMotion:IMotion = possibleMotions[uint(possibleMotions.length * Math.random())];
				dispatchEvent(new RequestMotionEvent(RequestMotionEvent.REQUEST_MOTION, finalMotion));
			}else {
				super.forfeight();
			}
		}
		
		private function _constructPossibleMotions(data:BoardData, peaceIndex:uint = 0):void {
			if (peaceIndex == 0) {
				_maxWeight = -Infinity;
				_possibleMotions = new Vector.<IMotion>();
			}
			
			var figurePositions:Vector.<PeacePosition> = data.getPeacesByColor(_color);
			
			var startTime:uint = getTimer();
			for (var i:int = peaceIndex; i < figurePositions.length; i++) {
				for (var j:int = 0; j < data.board.length; j++) {
					for (var k:int = 0; k < data.board[j].length; k++) {
						data.rollBackAll();
						var sP:PeacePosition = figurePositions[i];
						var fP:PeacePosition = new PeacePosition(k, j);
						if (_controller.processMotion(sP, fP, true)) {
							var motion:BaseMotion = new BaseMotion(_controller, sP, fP);
							if (motion.weight > _maxWeight) {
								_possibleMotions = new Vector.<IMotion>();
								_maxWeight = motion.weight;
							}
							if (motion.weight == _maxWeight) {
								_possibleMotions.push(motion);
							}
						}
					}
				}
				if (getTimer() - startTime > 15) {
					_t = setTimeout(_constructPossibleMotions, 0, data, i + 1);
					return;
				}
			}
			dispatchEvent(new Event(ACTIONS_CONSTRUCTED));
		}
		
		override public function chosePeace():void {
			super.selectPeace(super.missingPeaces[super.missingPeaces.length - 1]);
		}
		
		//--------------------------------------------------------------------------
		//
		//  EVENT HANDLERS
		//
		//--------------------------------------------------------------------------
		
		private function _onPlayerChanged(e:ServerGameEvent):void {
			if (_data.currentPlayer == this) {
				this.doMotion();
			}
		}
		
		
		private function _onPeaceChanged(e:ServerGameEvent):void {
			if (_data.lastChangedPeaceType != PeaceType.WHITE_KNIAZ && _data.lastChangedPeaceType != PeaceType.BLACK_KNIAZ) return;
			if (_data.currentPlayer == this) {
				this.doMotion();
			}
		}
		
		
	}

}

//--------------------------------------------------------------------------
//
//  INNER DEFINITIONS
//
//--------------------------------------------------------------------------

import by.kniazhych.core.constants.PeaceType;
import by.kniazhych.core.data.game.PeaceData;
import by.kniazhych.core.data.game.PeacePosition;
import by.kniazhych.core.server.local.core.IMotion;
import by.kniazhych.core.server.local.data.MotionCommand;
import by.kniazhych.core.server.local.rules.IPlayer;
import by.kniazhych.core.server.local.ai.TestLogicController;

interface ILogicMotion extends IMotion {
	function get weight():Number;
}

class BaseMotion implements ILogicMotion {
	
	private static const _RANKS:Object = { };
	_RANKS[PeaceType.BLANK_CELL] = 0;
	_RANKS[PeaceType.BLACK_PAWN] = 1;
	_RANKS[PeaceType.WHITE_PAWN] = 1;
	_RANKS[PeaceType.BLACK_GARMATA] = 3;
	_RANKS[PeaceType.WHITE_GARMATA] = 3;
	_RANKS[PeaceType.BLACK_VAUKALAK] = 3;
	_RANKS[PeaceType.WHITE_VAUKALAK] = 3;
	_RANKS[PeaceType.BLACK_LADZIA] = 4;
	_RANKS[PeaceType.WHITE_LADZIA] = 4;
	_RANKS[PeaceType.BLACK_GETMAN] = 6; 
	_RANKS[PeaceType.WHITE_GETMAN] = 6; 
	_RANKS[PeaceType.BLACK_KNIAZHYCH] = 6;
	_RANKS[PeaceType.WHITE_KNIAZHYCH] = 6; 
	_RANKS[PeaceType.BLACK_KNIAZ] = 7;
	_RANKS[PeaceType.WHITE_KNIAZ] = 7;
	
	private static const _INICIATIVA:Object = { };
	_INICIATIVA[PeaceType.BLACK_PAWN] = 0.1;
	_INICIATIVA[PeaceType.WHITE_PAWN] = 0.1;
	_INICIATIVA[PeaceType.BLACK_GARMATA] = 0.1;
	_INICIATIVA[PeaceType.WHITE_GARMATA] = 0.1;
	_INICIATIVA[PeaceType.BLACK_VAUKALAK] = 0.1;
	_INICIATIVA[PeaceType.WHITE_VAUKALAK] = 0.1;
	_INICIATIVA[PeaceType.BLACK_LADZIA] = 0.1;
	_INICIATIVA[PeaceType.WHITE_LADZIA] = 0.1;
	_INICIATIVA[PeaceType.BLACK_GETMAN] = 0.1; 
	_INICIATIVA[PeaceType.WHITE_GETMAN] = 0.1; 
	_INICIATIVA[PeaceType.BLACK_KNIAZHYCH] = 0.2;
	_INICIATIVA[PeaceType.WHITE_KNIAZHYCH] = 0.2; 
	_INICIATIVA[PeaceType.BLACK_KNIAZ] = 0.2;
	_INICIATIVA[PeaceType.WHITE_KNIAZ] = 0.2;
	
	private var _sP:PeacePosition;
	private var _fP:PeacePosition;
	private var _controller:TestLogicController;
	
	public function BaseMotion(controller:TestLogicController, sP:PeacePosition, fP:PeacePosition) {
		_controller = controller;
		_fP = fP;
		_sP = sP;
	}
	
	/* INTERFACE by.kniazhych.core.server.local.ai.IMotion */
	
	public function get sP():PeacePosition{
		return _sP;
	}
	
	public function get fP():PeacePosition{
		return _fP;
	}
	public function get weight():Number{
		var w:Number = _takenPeaceRank + _tronBonus - (_attackPeaceRank / 10);
		_controller.data.test(new MotionCommand(sP, fP));
		w += _oponentUnderCheckBonus + _promovePawnBonus - _highestLostFigureRank;
		_controller.data.rollBack();
		return w;
	}
	
	//--------------------------------------------------------------------------
	//
	//  PRIVATE METHODS
	//
	//--------------------------------------------------------------------------
	
	private function get _promovePawnBonus():uint {
		return _controller.data.currentPlayer.canPromovePawn ? 3 : 0;
	}
	
	private function get _highestLostFigureRank():uint {
		var myPeaces:Vector.<PeacePosition> = _controller.data.getPeacesByColor(_controller.data.currentPlayer.color);
		var oppPeaces:Vector.<PeacePosition> = _controller.data.getPeacesByColor(_controller.data.opponentPlayer.color);
		var maxRank:uint = 0;
		for (var i:int = 0; i < oppPeaces.length; i++) {
			for (var j:int = 0; j < myPeaces.length; j++) {
				if (_controller.processMotion(oppPeaces[i], myPeaces[j], true)) {
					maxRank = Math.max(maxRank, _controller.data.getCellState(myPeaces[j]));
				}
			}
		}
		return maxRank;
	}
	
	private function get _oponentUnderCheckBonus():uint {
		return _controller.data.opponentPlayer.isUnderCheck ? 1 : 0;
	}
	
	private function get _takenPeaceRank():uint {
		return _RANKS[_controller.data.getCellState(_fP)];
	}
	
	private function get _attackPeaceRank():uint {
		return _RANKS[_controller.data.getCellState(_sP)];
	}
	
	private function get _tronBonus():uint {
		return _fP.x == 4 && _fP.y == 4 ? 3 : 0;
	}
	
	
	
}